# coding: utf-8

import json
from datetime import datetime
import random

from flask import request, current_app
from flask_restful import Api, Resource

from app.extensions import db
from app.api.auth_codes import CAPTCHA_NOT_EXIST, CAPTCHA_NOT_MATCH
from app.api.codes import PARAMS_ILLEGAL
from app.api.constant import APP_TOKEN_TIMEOUT
from app.api.utils import generate_captcha
from app.api_v2.user_schemas import user_info_schema
from app.api_v2.views import Response
from app.api_v2.auth_schemas import app_login_schema, app_mobile_schema
from app.api_v2.utils import ip_to_area
from app.api_v2.constant import VERIFY_MOBILE
from app.api.codes import SUCCESS
from app.msg.models import SMSLog
from app.op.constant import UserType, UserLevel, UserActive, TRIAL_VOUCHER_CNT
from app.op.models import User, UserProtocol, UserInfo, Area
from app.relationship.constant import FriendStatus, InviteSource
from app.relationship.models import MobileList, InviteLog
from app.token import AuthToken
from app.utils import MsgProxy
from app.wph_lib import alidayu
from app.auth.constant import CaptchaSmsChannel, PROTOCOL_VERSION_KEY
from common.bid_notify.message import MessageNotify
from common.constant import Captcha_Sms_Channel_Key, APP_USER_ID_KEY, \
    VoucherStatType, GiveVoucherReason
from app.msg.utils import generate_sms_content
from common.im_util import CS_ACCID2
from app.enterprise.models import Enterprise
from app.enterprise.constant import EnterpriseLevel

api = Api()


@api.resource('/login')
class AppLoginResource(Resource):
    """
    create by ld_wu 2017-11-20
    注册/登录
    """

    def post(self):
        data, errors = app_login_schema.load(request.get_json())
        if errors:
            return Response(
                PARAMS_ILLEGAL.new_format_msg(list(errors.values())[0][0])
            )

        verify = False
        mobile = data['mobile']
        if mobile in VERIFY_MOBILE:
            captcha = '1234'
            verify = True
        else:
            captcha = current_app.redis.get('captcha_{}'.format(mobile))
            if not captcha:
                return Response(CAPTCHA_NOT_EXIST)

        if captcha != data['sms_captcha']:
            return Response(CAPTCHA_NOT_MATCH)

        user = User.get_by_args(mobile=mobile)
        if not user:
            prov, city = ip_to_area(request.remote_addr)
            user = User.create(
                mobile=mobile,
                nickname=mobile,
                type=UserType.ENGINEER.value,
                level=UserLevel.LEVEL_2.value,
                prov=prov.name,
                city=city.name,
                area_id=city.id
            )
            # 用户注册时，更新通讯的用户id
            MobileList.query.filter(
                MobileList.mobile == mobile,
                MobileList.followed_id.is_(None)
            ).update(
                dict(
                    followed_id=user.id,
                    status=FriendStatus.DEFAULT
                ),
                synchronize_session='fetch'
            )
            # 签署用户协议
            protocol_version = current_app.redis.get(PROTOCOL_VERSION_KEY) or ''
            if protocol_version and not UserProtocol.get_by_args(
                    user_id=user.id,
                    version=protocol_version
            ):
                UserProtocol.create(
                    user_id=user.id,
                    mobile=user.mobile,
                    nickname=user.nickname,
                    version=protocol_version
                )

        # 只要该用户之前没有app邀请人信息, 均需要写入此信息
        # 如果用户之前已经登录过app,则不写入app邀请人
        user_info = UserInfo.default_user_info(user.id)
        user_info.app_login_version = data.get('app_login_version', '')
        if not user_info.app_invite_user_id and not user_info.app_first_login_time:
            user_info.app_first_login_time = datetime.now()

            # 写入邀请人
            app_invite_user_id = data.get('app_invite_user_id', None)
            if app_invite_user_id:
                # 被邀请人直接想邀请人发起好友申请
                InviteLog.invite_friend(
                    user.id,
                    app_invite_user_id,
                    source=InviteSource.MY_INVITE.value
                )
                app_invite_user = User.get_by_id(app_invite_user_id)

                invite_user_info = UserInfo.default_user_info(app_invite_user.id)

                user_info.app_invite_user_id = app_invite_user_id
                # 如果邀请人的app_root_invite_user_id为0,则表示他为根节点,此时把邀请人的id写入此用户的根节点
                user_info.app_root_invite_user_id = (
                    invite_user_info.app_root_invite_user_id or app_invite_user_id
                )

                # 先查根节点是否有运营中心，有则沿用
                root_invite_user_info = UserInfo.get_by_id(
                    user_info.app_root_invite_user_id
                )
                if root_invite_user_info.operation_center_id:
                    user_info.operation_center_id = \
                        root_invite_user_info.operation_center_id
                # 否则根据用户手机号归属地查询运营中心，并随机取一个
                # 如果该地没有运营中心，从广东省随机分配一个运营中心给用户
                # 440000为广东省地区ID
                # FIXME 有两个运营中心是金银牌，这里会查不出来。后续优化
                else:
                    area = Area.get_by_id(
                        user.phone_area_id if user.phone_area_id else 0
                    )
                    enterprises = area.enterprises.filter(
                        Enterprise.level == EnterpriseLevel.OP_CENTER.value
                    ).all() if area else []
                    if enterprises:
                        user_info.operation_center_id = \
                            random.choice(enterprises).id

                # 如果根节点跟当前邀请人id不是同一个id时
                # 需要去更新好友的推荐通讯录信息
                if (
                    user_info.app_root_invite_user_id and
                    user_info.app_root_invite_user_id != app_invite_user_id
                ):
                    # 如果没有invite_logs记录写入一条status=0的记录
                    # 根节点用户可以看到+好友的按钮
                    # 避免少数情况下的下线邀请的来源显示问题
                    log = InviteLog.get_by_args(
                        follower_id=user.id,
                        followed_id=user_info.app_root_invite_user_id
                    )
                    if not log:
                        InviteLog.create(
                            follower_id=user.id,
                            followed_id=user_info.app_root_invite_user_id,
                            status=FriendStatus.DEFAULT,
                            source=InviteSource.SUBORDINATE.value,
                            invite_name=app_invite_user.nickname,
                            read_status=True
                        )

                # 通知上线(下线是针对父节点而言的)
                MessageNotify.app_invite_new_user_notify(
                    db.session, User.get_by_id(user_info.app_root_invite_user_id), user, datetime.now()
                )

        if not current_app.redis.sismember(APP_USER_ID_KEY, user.id):

            # app 首次登录发送消息
            msg = """嘿，来了？这里已经发了数万条LED显示屏订单，快去看看您所在城市的订单吧！"""
            proxy = MsgProxy()
            proxy.im_msg_producer.new_arrival_msg(
                CS_ACCID2,
                user.id,
                msg,
                '欢迎使用万屏汇'
            )

        if not user.pack:
            user.type = UserType.ENGINEER.value
            user.level = UserLevel.LEVEL_2.value
            user.active = UserActive.ACTIVE.value

            # 新用户或者拉新用户赠送汇币
            user.gift_bid_point()
            # app通知
            proxy = MsgProxy()
            proxy.im_msg_producer.app_give_voucher_notify(
                user_id=user.id, count=TRIAL_VOUCHER_CNT
            )
            # 触发代金券统计生产者
            current_app.common_producer.send(
                json.dumps(
                    dict(
                        backend='voucher_stat',
                        func='day_stat',
                        kwargs=dict(
                            voucher_stat_type=VoucherStatType.GRANT.value,
                            reason=GiveVoucherReason.SYSTEM_GIFT.value,
                            user_id=user.id,
                            stat_cnt=TRIAL_VOUCHER_CNT,
                        )
                    )
                )
            )

        token = AuthToken.generate_app_token(APP_TOKEN_TIMEOUT, user)

        user_info = user_info_schema.dump(user)[0]
        user_info['verify'] = verify
        return Response(body=dict(token=token, user=user_info))


@api.resource('/send_captcha')
class AppSmsResource(Resource):
    """
    create by ld_wu 2017-11-20
    发送验证码
    """

    def get(self):
        data, errors = app_mobile_schema.load(request.args)
        if errors:
            return Response(
                PARAMS_ILLEGAL.new_format_msg(list(errors.values())[0][0]))

        mobile = data['mobile']
        key = 'captcha_{}'.format(mobile)
        captcha_sms_channel = current_app.redis.get(Captcha_Sms_Channel_Key) \
            or CaptchaSmsChannel.MENG_WANG.value
        captcha = current_app.redis.get(key)
        if not captcha:
            if captcha_sms_channel == CaptchaSmsChannel.NA.value:
                captcha = '1234'
            else:
                captcha = generate_captcha()
            current_app.redis.set(key, captcha, ex=30 * 60)

        template_code = 'NA'
        if captcha_sms_channel == CaptchaSmsChannel.MENG_WANG.value:
            template_code = 'CAPTCHA'
            content = generate_sms_content(
                template_code=template_code,
                captcha=captcha
            )
            current_app.captcha_producer.send(
                json.dumps({
                    'mobile': mobile,
                    'content': content,
                })
            )
        elif captcha_sms_channel == CaptchaSmsChannel.ALI_DA_YU.value:
            # 使用阿里大于发送短信
            template_code = 'SMS_52355022'
            req = alidayu.api.AlibabaAliqinFcSmsNumSendRequest()
            req.set_app_info(
                alidayu.appinfo('23382326', 'd6932553edc60a55fdd84e6efb1bd262'))
            req.sms_type = 'normal'
            req.rec_num = mobile
            req.sms_template_code = template_code
            req.sms_free_sign_name = 'LED屏'
            req.sms_param = {'captcha': captcha}
            req.getResponse()
        SMSLog.create(
            mobile=mobile,
            template_code=template_code,
            content=captcha,
        )

        return Response(SUCCESS)



